function improved_svm_training_patch()
% 改进SVM训练的补丁函数
% 修复FaceRecognitionApp.m中SVM识别准确率不稳定的问题

fprintf('===== SVM训练稳定性补丁 =====\n');
fprintf('本补丁解决以下问题:\n');
fprintf('1. SVM参数自动调优导致的不稳定性\n');
fprintf('2. 训练数据选择的随机性\n');
fprintf('3. PCA降维过程中的符号不一致\n');
fprintf('4. 缺乏模型验证和参数优化\n\n');

% === 主要修复方案 ===

fprintf('【修复方案1】固定随机种子\n');
fprintf('在trainModel函数开始处添加:\n');
fprintf('rng(42, ''twister'');  %% 确保结果可重现\n\n');

fprintf('【修复方案2】替换SVM训练代码\n');
fprintf('将以下不稳定的代码:\n');
fprintf('appData.svmModel = fitcecoc(X_train, Y_train, ...\n');
fprintf('    ''Learners'', templateSVM(''KernelFunction'', ''rbf'', ...\n');
fprintf('                           ''KernelScale'', ''auto'', ...)  %% 问题所在\n\n');

fprintf('替换为稳定版本:\n');
fprintf('%% 使用交叉验证优化参数\n');
fprintf('bestParams = optimizeSVMParameters(X_train, Y_train);\n');
fprintf('appData.svmModel = fitcecoc(X_train, Y_train, ...\n');
fprintf('    ''Learners'', templateSVM(''KernelFunction'', ''rbf'', ...\n');
fprintf('                           ''KernelScale'', bestParams.kernelScale, ...\n');
fprintf('                           ''BoxConstraint'', bestParams.boxConstraint, ...\n');
fprintf('                           ''Standardize'', true));\n\n');

fprintf('【修复方案3】稳定的训练数据选择\n');
fprintf('将随机选择:\n');
fprintf('selectedIndices = personFileIndices(randperm(numAvailable, numToUse));\n\n');
fprintf('替换为按序号排序选择:\n');
fprintf('[~, sortOrder] = sort(personSequences);\n');
fprintf('selectedIndices = personFileIndices(sortOrder(1:numToUse));\n\n');

% 提供具体的修复函数
fprintf('【修复方案4】添加SVM参数优化函数\n');

end

function bestParams = optimizeSVMParameters(X_train, Y_train)
% SVM参数优化函数 - 使用网格搜索和交叉验证

fprintf('    开始SVM参数优化...\n');

% 参数搜索空间
kernelScales = [0.1, 0.5, 1.0, 2.0, 5.0];
boxConstraints = [0.1, 1, 10, 100];

bestAccuracy = 0;
bestParams = struct('kernelScale', 1.0, 'boxConstraint', 1);

% 5折交叉验证
cv = cvpartition(Y_train, 'KFold', 5);

for i = 1:length(kernelScales)
    for j = 1:length(boxConstraints)
        ks = kernelScales(i);
        bc = boxConstraints(j);
        
        % 交叉验证评估
        accuracies = [];
        for fold = 1:5
            trainIdx = training(cv, fold);
            testIdx = test(cv, fold);
            
            % 训练临时模型
            tempModel = fitcecoc(X_train(trainIdx, :), Y_train(trainIdx), ...
                'Learners', templateSVM('KernelFunction', 'rbf', ...
                                       'KernelScale', ks, ...
                                       'BoxConstraint', bc, ...
                                       'Standardize', true), ...
                'Verbose', 0);
            
            % 预测和评估
            predictions = predict(tempModel, X_train(testIdx, :));
            accuracy = mean(predictions == Y_train(testIdx)) * 100;
            accuracies(end+1) = accuracy;
        end
        
        avgAccuracy = mean(accuracies);
        if avgAccuracy > bestAccuracy
            bestAccuracy = avgAccuracy;
            bestParams.kernelScale = ks;
            bestParams.boxConstraint = bc;
        end
        
        fprintf('    KS=%.1f, BC=%.1f: %.2f%%\n', ks, bc, avgAccuracy);
    end
end

fprintf('    最优参数: KS=%.1f, BC=%.1f, 准确率=%.2f%%\n', ...
        bestParams.kernelScale, bestParams.boxConstraint, bestAccuracy);

end

function stablePCAResult = performStablePCA(trainFaces, meanFace, pcaRatio)
% 稳定的PCA降维函数

% 计算协方差矩阵
C = trainFaces' * trainFaces;
[V, D] = eig(C);

% 按特征值排序
eigenValues = diag(D);
[eigenValues, sortIdx] = sort(eigenValues, 'descend');
V = V(:, sortIdx);

% 选择主成分
cumSum = cumsum(eigenValues) / sum(eigenValues);
numComponents = find(cumSum >= pcaRatio, 1);
if isempty(numComponents)
    numComponents = length(eigenValues);
end

selectedV = V(:, 1:numComponents);

% 计算特征脸并确保符号一致性
eigenFaces = trainFaces * selectedV;

% 标准化特征脸并确保符号一致
for i = 1:size(eigenFaces, 2)
    eigenFace = eigenFaces(:, i);
    % 确保第一个非零元素为正
    firstNonZero = find(abs(eigenFace) > 1e-10, 1);
    if ~isempty(firstNonZero) && eigenFace(firstNonZero) < 0
        eigenFaces(:, i) = -eigenFace;
        selectedV(:, i) = -selectedV(:, i);
    end
    
    % 标准化
    norm_val = norm(eigenFaces(:, i));
    if norm_val > 0
        eigenFaces(:, i) = eigenFaces(:, i) / norm_val;
    end
end

% 投影训练数据
projectMatrix = eigenFaces;
weightedTrain = projectMatrix' * trainFaces;

stablePCAResult = struct();
stablePCAResult.eigenFaces = eigenFaces;
stablePCAResult.projectMatrix = projectMatrix;
stablePCAResult.weightedTrain = weightedTrain;

end

function [selectedFiles, selectedLabels] = selectTrainingDataStable(allFiles, trainImgPerPerson)
% 稳定的训练数据选择函数

% 按文件名排序确保一致性
[~, sortIdx] = sort({allFiles.name});
allFiles = allFiles(sortIdx);

% 解析文件名并分组
personData = containers.Map('KeyType', 'int32', 'ValueType', 'any');

for i = 1:length(allFiles)
    filename = allFiles(i).name;
    tokens = regexp(filename, '(\d+)[-_](\d+)', 'tokens');
    
    if ~isempty(tokens)
        personID = str2double(tokens{1}{1});
        imageSeq = str2double(tokens{1}{2});
        
        if isKey(personData, personID)
            data = personData(personID);
            data.sequences(end+1) = imageSeq;
            data.fileIndices(end+1) = i;
            personData(personID) = data;
        else
            data = struct();
            data.sequences = imageSeq;
            data.fileIndices = i;
            personData(personID) = data;
        end
    end
end

% 稳定选择训练图像
personIDs = sort(cell2mat(keys(personData)));
selectedFiles = [];
selectedLabels = [];

for i = 1:length(personIDs)
    personID = personIDs(i);
    data = personData(personID);
    
    % 按序号排序
    [~, sortOrder] = sort(data.sequences);
    sortedIndices = data.fileIndices(sortOrder);
    
    % 选择前N张
    numToUse = min(trainImgPerPerson, length(sortedIndices));
    selectedIndices = sortedIndices(1:numToUse);
    
    for j = 1:length(selectedIndices)
        selectedFiles(end+1) = selectedIndices(j);
        selectedLabels(end+1) = personID;
    end
end

end 